package org.jeecg.modules.cascv.image.controller;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.lineparser.Line;
import org.jeecg.common.lineparser.LineParser;
import org.jeecg.config.TaskExecutePool;
import org.jeecg.modules.cascv.image.entity.GmvVideo;
import org.jeecg.modules.cascv.image.service.IGmvVideoService;
import org.jeecg.modules.cascv.image.service.impl.MergeImageService;
import org.jeecg.modules.cascv.image.util.LaptopConstant;
import org.jeecg.modules.cascv.rabbitmq.RabbitMQConfig;
import org.jeecg.modules.message.websocket.WebSocket;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/**
 * @Description: ids图片播放
 * @Author: jeecg-boot
 * @Date: 2022-08-31
 * @Version: V1.0
 */
@Slf4j
@Api(tags = "ids图片播放")
@RestController
@RequestMapping("/test/gmvVideo")
public class GmvImageController {
    @Autowired
    private IGmvVideoService gmvVideoService;
    @Resource
    private WebSocket webSocket;
    @Value("${jeecg.path.upload}")
    private String upLoadPath;
    @Autowired
    private MergeImageService mergeImageService;

    private AtomicBoolean test_lock = new AtomicBoolean(false);
    private String file_path = "/data/images/";

    @Autowired
    private TaskExecutePool taskExecutePool;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 分页列表查询
     *
     * @param gmvVideo
     * @param index
     * @param count
     * @param req
     * @return
     */
//    @AutoLog(value = "ids图片播放-分页列表查询")
    @ApiOperation(value = "ids图片播放-分页列表查询", notes = "ids图片播放-分页列表查询")
    @RequestMapping(value = "/list", produces = "application/json;charset=utf-8")
    @ResponseBody
    public Result<?> queryPageList(GmvVideo gmvVideo,
                                   @RequestParam(name = "index", defaultValue = "1") Integer index,
                                   @RequestParam(name = "count", defaultValue = "10") Integer count,
                                   HttpServletRequest req) {

        String idsName = gmvVideo.getIdsName();
        String fileId = gmvVideo.getFileId();
        String key = StringUtils.isNotEmpty(idsName) ? idsName : fileId;

        //从现有的缓存中获取，如果缓存中有key，则返回value，如果没有则返回null
        List<JSONObject> images = LaptopConstant.infoMap.get(key);
        if (CollectionUtil.isEmpty(images)) {
            return Result.OK(images);
        }
        if (index - 1 > images.size()) {
            return Result.OK();
        }
        int end = index - 1 + count;
        if (end > images.size()) {
            end = images.size();
        }

        List<JSONObject> gmvVideos = new LinkedList<>();
        for (int i = index - 1; i < end; i++) {
            JSONObject jsonObject = images.get(i);
            jsonObject.put("index", i);
            gmvVideos.add(jsonObject);
        }

        IPage<JSONObject> page = new Page<>();
        page.setRecords(gmvVideos); //存入当前页记录
        page.setTotal(images.size());//存入数据总记录数

        //  long time2 = System.currentTimeMillis();
        //  time2 = time2-time1;
        // log.info("调用list接口需要的时间"+time2);
        return Result.OK(page);
    }

    /**
     * 分页列表查询
     *
     * @param gmvVideo
     * @param req
     * @return
     */
//    @AutoLog(value = "ids图片播放-分页列表查询")
    @ApiOperation(value = "ids图片播放-分页列表length查询", notes = "ids图片播放-分页列表length查询")
    @RequestMapping(value = "/count", produces = "application/json;charset=utf-8")
    @ResponseBody //把数据展示到前端页面
    public Result<?> queryPageCount(GmvVideo gmvVideo,
                                    HttpServletRequest req) {
        //   long time1 = System.currentTimeMillis();
        String idsName = gmvVideo.getIdsName();
        String fileId = gmvVideo.getFileId();

        String key = StringUtils.isNotEmpty(idsName) ? idsName : fileId;

        //从现有的缓存中获取，如果缓存中有key，则返回value，如果没有则返回null
        List<JSONObject> images = LaptopConstant.infoMap.get(key);
        if (CollectionUtil.isEmpty(images)) {
            return Result.OK(images);
        }
        //   log.info("key=" + key + ",count=" + images.size());
        IPage<JSONObject> page = new Page<>();
        page.setTotal(images.size());
        //  long time2 = System.currentTimeMillis();
        //  time2 = time2-time1;
        //    log.info("调用分页列表length查询 接口需要的时间=="+time2);
        return Result.OK(page);
    }


    /**
     * 图片合成解析
     *
     * @param jsonObject
     * @return
     */
//    @AutoLog(value = "ids图片播放-图片合成解析")
    @ApiOperation(value = "ids图片播放-图片合成解析", notes = "ids图片播放-图片合成解析")
    @RequestMapping(value = "/compositeImg")//请求地址映射的注解
    public Result<?> compositeImg(@RequestBody JSONObject jsonObject, HttpServletRequest request) {//@RequestBody接收前端的参数
        Result<Object> error = mergeImageService.mergeImage(jsonObject, null);
        return Result.OK();
    }

    @ApiOperation(value = "ids图片播放-实时测试接口", notes = "ids图片播放-实时测试接口")
    @RequestMapping(value = "/testReal") //测试接口调用这个
    public Result<?> test(HttpServletRequest request, String idsName) throws Exception {

        boolean lock = test_lock.compareAndSet(false, true); //开始为true
        if (!lock) {
            return Result.OK();
        }

//        /data/workspace/laptop-java/files
//        String filePath = "//files//TGTHYY0401_090H_31_CMPRAPP5.txt";
        try {
            log.info("idsname==>" + idsName); //日志打印
            //  String filePath = "//files//"+idsName +".txt";
            String filePath = "E:\\11图像数据完整的\\流体物理实验柜1301\\高分辨CCD图像数据.txt";
            log.info("filePath" + filePath);
            LaptopConstant.infoMap.remove("TGMTYY1301_06BH_31_FPRAPP1");

            for (int i = 0; i < 100; i++) {
                RandomAccessFile randomAccessFile = new RandomAccessFile(filePath, "r");
                while (true) {
                    String jsonStr = randomAccessFile.readLine();
                    if (jsonStr == null) {
                        log.info("while循环结束！！！");
                        break;
                    }
                    //避免读取乱码
                    jsonStr = new String(jsonStr.getBytes("ISO-8859-1"), "utf-8");
                    rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_NAME, "boot.haha", jsonStr);
                    // JSONObject jsonObject = JSONObject.parseObject(jsonStr); //将字符串转为JSONObject
                    // mergeImageService.mergeImage(jsonObject, null);
                }
            }
            return Result.OK();
        } finally {
            test_lock.set(false);
        }
    }


    @ApiOperation(value = "心跳接口", notes = "心跳接口")
    @GetMapping(value = "/heartbeat")
    public Result<?> heartbeat(String fileId) {
        Result<?> result = new Result<>();
        LaptopConstant.timeMap.put(fileId, System.currentTimeMillis() + 1000 * 10);
        result.success("操作成功");
        return result;
    }

    @ApiOperation(value = "文件上传", notes = "文件上传")
    @PostMapping(value = "/uploadFile")
    @CrossOrigin
    public Result<?> uploadFile(HttpServletRequest request) {
        long time = System.currentTimeMillis();
        Result<String> result = new Result<>();
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        MultipartFile file = multipartRequest.getFile("file");

        if (file == null) return Result.error("文件不能为空！");
        FileOutputStream out = null;
        String fileId = IdWorker.get32UUID();
        String filePath = upLoadPath + File.separator + file.getOriginalFilename();
        LaptopConstant.filePathMap.put(fileId, filePath);
        FileUtil.touch(filePath); //创建文件及其父目录，如果这个文件存在，直接返回这个文件 此方法不对File对象类型做判断，如果File不存在，无法判断其类型

        try {
            out = new FileOutputStream(new File(filePath));
            out.write(file.getBytes());
            out.flush();
            LaptopConstant.threadMap.put(fileId, true);
//            Thread thread = new Thread() {
//                @Override
//                public void run() {
//                    imageByFile(fileId);
//                }
//            };
//            thread.start();
            taskExecutePool.threadPoolTaskExecutor().execute(new Runnable() {
                @Override
                public void run() {
                    imageByFile(fileId);
                }
            });

        } catch (Exception e) {
            log.error("文件上传失败！", e);
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        result.setResult(fileId);
        result.success("操作成功");
        long time2 = System.currentTimeMillis();
        time2 = time2 - time;
        log.info("文件上传时间" + time2);
        return result;
    }
//

    @ApiOperation(value = "ids图片获取", notes = "ids图片获取")
    @RequestMapping(value = "/getImage/{imageName}") //传递图片
    public void getImage(@PathVariable String imageName, HttpServletRequest request, HttpServletResponse response) {

        imageName = "/data/images/" + imageName;
        FileInputStream fis = null;
        OutputStream os = null;
        File file = new File(imageName);
        if (file.exists()) {
            try {
                fis = new FileInputStream(file);
                long size = file.length();
                byte[] temp = new byte[(int) size];
                fis.read(temp, 0, (int) size);// 读取数据
                fis.close();
                byte[] data = temp;
                response.setContentType("image/png");
                os = response.getOutputStream();//获取输出流
                os.write(data); //输出数据
                os.flush();
                os.close();

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    //@RequestBody List<Integer> imgList,
    @CrossOrigin
    @ApiOperation(value = "文件下载", notes = "文件下载")
    @PostMapping(value = "/download",produces = "application/json;charset=utf-8")  // @RequestBody  , @RequestParam(value="fileListNum") List<String> fileListNum,@RequestParam(value="fileId")String fileid
        public  void downloadImages(@RequestBody GmvVideo gmvVideo,HttpServletResponse response) {
        String fileid = gmvVideo.getFileId();
        List<String> fileListNum = gmvVideo.getFileListNum();
        //创建文件名集合
        List<String> imageFiles = new ArrayList<>();
        List<JSONObject> list = LaptopConstant.infoMap.get(fileid);
        if (null == list) {
            return;
        }
        //将对应的文件名存入list
        for (String imgId : fileListNum) {
            JSONObject jsonObject = list.get(Integer.parseInt(imgId));
            String imageUrl = jsonObject.getString("imageUrl");
            String fileName = imageUrl.substring(57);
            imageFiles.add(file_path + fileName);
        }

        //创建压缩文件的名称
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        String time = sdf.format(new Date());
        String zipFileName = time + ".zip"; // zip文件名

        //把文件进行压缩成文件流
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ZipOutputStream zos = new ZipOutputStream(baos);

        try {
            for (String fileName : imageFiles) {
                File file = new File(fileName);
                FileInputStream fis = new FileInputStream(file);
                ZipEntry zipEntry = new ZipEntry(file.getName());
                zos.putNextEntry(zipEntry);
                byte[] bytes = new byte[1024];
                int length;
                while ((length = fis.read(bytes)) >= 0) {
                    zos.write(bytes, 0, length);
                }
                fis.close();
                zos.closeEntry();
            }
            zos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        byte[] zipBytes = baos.toByteArray();
            // 设置响应头
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", "attachment; filename=\""+zipFileName+"\"");
            response.setContentLength(zipBytes.length);

            // 写入响应内容
        try {
            OutputStream out = response.getOutputStream();
            out.write(zipBytes);
            out.flush();
            out.close();
            baos.close();
        } catch (IOException e) {
            log.info("生成.zip文件报错");
            e.printStackTrace();
        }


    }



    public void imageByFile(String fileId) {
        try {
            String filePath = LaptopConstant.filePathMap.get(fileId);
            LineParser parser = new LineParser(Integer.MAX_VALUE, 0); //初始化读取工具
            Path path = Paths.get(filePath);
            Charset cs = StandardCharsets.UTF_8;
            try {
                parser.forEach(path, cs, new Consumer<Line>() {
                    @Override
                    public void accept(Line line) {
                        String jsonStr = line.getContent().toString();
                        if (jsonStr == null) {
                            return;
                        }
                        if (!LaptopConstant.threadMap.containsKey(fileId)) {
                            throw new RuntimeException("有新的上传文件");
                        }
                        JSONObject jsonObject = JSONObject.parseObject(jsonStr); //将jsonStr转换为json对象
                        mergeImageService.mergeImage(jsonObject, fileId);
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("添加视屏图片帧失败", e);
        }
    }





}
